open Ast

(*set this to true for debugging output*)
let debug = "false"

(*******************************************************************************************)
let split_str sep str = 
  Str.split(Str.regexp_string sep) str

(*custom point type stores longitude/latitude*)
class point = 
object
  val mutable longitude = 0.000000
  val mutable latitude = 0.000000
  method get_longitude = longitude
  method get_latitude = latitude
  method set_longitude long = longitude <- long
  method set_latitude lat = latitude <- lat
end;;

(*global test point for storing elements as point type*)
let testPoint = new point
let point = new point

(*custom path type for roads*)
class path = 
object
  val mutable name = "null"
  val mutable pathType = "null"
  val mutable numberOfPoints = 0
  val mutable points = Array.make 100 testPoint
  method get_name = name
  method get_pathType = pathType
  method get_numberOfPoints = numberOfPoints
  method get_points = points
  method set_name n = name <- n
  method set_pathType p = pathType <- p
  method set_numberOfPoints n = numberOfPoints <- n
  method set_points p = points <- p 
end;; 

(*stores the mapObject*)
class mapObject = 
object
  val mutable name = "null"
  val mutable objectType = "null"
  val mutable speed = 0
  val mutable point = Array.make 1 testPoint
  method get_name = name
  method get_objectType = objectType
  method get_point = point
  method get_speed = speed
  method set_name n = name <- n
  method set_objectType o = objectType <- o
  method set_speed s = speed <- s
  method set_point p = point <- p
end;; 

(*custom intersection object/intersection*)
class intersection =
object 
  val mutable name = "null"
  val mutable weight = infinity
  val mutable path_one = "null"
  val mutable path_two = "null"
  val mutable point = new point
  method get_name = name
  method get_weight = weight
  method get_path_one = path_one
  method get_path_two = path_two
  method get_point = point
  method set_name n = name <- n
  method set_weight w = weight <- w
  method set_path_one p1 = path_one <- p1
  method set_path_two p2 = path_two <- p2
  method set_point lat long = point#set_latitude long; point#set_longitude lat
end;;


(*Global Variables*)
let object_num = ref 0 (*to fill the ObjectArray below*)
let object_count = ref 0 (*keeps track of how many map objecs there are *)

let intersection_num = ref 0
let intersection_count = ref 0

let path_num = ref 0
let path_count = ref 0

(*counts total number of paths*)
let increment_path_count n =
  path_count := !path_count+1;
  if debug = "true" then
    Printf.printf "path count %i\n" path_count.contents

let increment_mapObject_count n  =
  object_count := !object_count+1;
  if debug = "true" then
    Printf.printf "map object count %i\n" object_count.contents

let increment_intersection_count n =
  intersection_count := !intersection_count+1;
  if debug = "true" then
    Printf.printf "map object count %i\n" intersection_count.contents

(*sets a point type*)
let init_point longitude latitude = 
  let new_point = new point in
  new_point#set_longitude longitude;
  new_point#set_latitude latitude;
  if debug = "true" then
    Printf.printf "successfully created a new point\n" 

(*goes through the xml file first to count the number of each instance of a object type*)
let xml_parser =
  let x = Xml.parse_file "MapMeObjects.xml" in
  Xml.iter (function
  Xml.Element ("myobject", attrs, _) ->
    List.iter (function ("description", desc) -> 
      if desc = "path" then
	let name = List.assoc "name" attrs in
	increment_path_count name
      else if desc = "mapObject" then
	let name = List.assoc "name" attrs in
        increment_mapObject_count name
      else if desc = "intersection" then
        let name = List.assoc "name" attrs in
	increment_intersection_count name
      else if desc = "point\n" then
	if debug = "true" then
          Printf.printf "this is a point"
      else Printf.printf "not a recognizable object\n" | _ -> ()) attrs
    | _ -> ()) x

(*arrays that store the objects*)

(*map objects*)
let dummyMapObject = new mapObject (*for initializing*)
let object_named_arr = Array.make object_count.contents "null" (*name array*)
let objArray = Array.make object_count.contents dummyMapObject (*stores the actual map object*) 

(*path objects*)
let dummyPathObject = new path
let path_named_arr = Array.make path_count.contents "null"
let pathArray = Array.make path_count.contents dummyPathObject

(*intersection objects*)
let dummyintersectionObject = new intersection
let inters_named_arr = Array.make 1000 "null"
let intersArray = Array.make 1000 dummyintersectionObject

(*adds map object to the array*)
let add_mapObject name object_type point speed =
  let new_mapObject = new mapObject and
  new_point_array = Array.make 1 testPoint and
  dumb_point = new point and
  p = split_str "," point in
  (*variables := IntMap.add 4 object_num.contents !variables;*)
  new_mapObject#set_name name;
  new_mapObject#set_objectType object_type;
  new_mapObject#set_speed speed;
  (*create a point type for the object*)
  let x = float_of_string(List.nth p 0) and 
  y = float_of_string(List.nth p 1) in
  dumb_point#set_latitude x;
  dumb_point#set_longitude y;
  Array.set new_point_array 0 dumb_point;
  new_mapObject#set_point new_point_array;
  objArray.(object_num.contents) <- new_mapObject;
  object_named_arr.(object_num.contents) <- name;
  object_num := !object_num+1;
  if debug = "true" then
    Printf.printf "added map object:%s to array\n" new_mapObject#get_name

(*adds path object to the array*)
let add_path name path_type number_of_points points =
  (*init path array to set in the path object*)
  let new_point_array = Array.make number_of_points testPoint and
  new_path = new path in 
  new_path#set_name name;
  new_path#set_pathType path_type;
  new_path#set_numberOfPoints number_of_points;
  (*retrieve the list of points seperated by colons first*)
  let first_parse = split_str ";" points in
  (*let second_parse = split_str "," first_parse in*)
  for i = 0  to (new_path#get_numberOfPoints - 1) do
    let dumb_point = new point in
    let z1 = List.nth first_parse i in
    let x1 = split_str "," z1 in
    let x2 = float_of_string(List.nth x1 0) and
      y1 = float_of_string(List.nth x1 1) in
      dumb_point#set_latitude x2;
      dumb_point#set_longitude y1;
      Array.set new_point_array i dumb_point;
      if debug = "true" then
	Printf.printf "index: %i Added (%f, %f)\n" i new_point_array.(i)#get_latitude new_point_array.(i)#get_longitude;
  done;
 if debug = "true" then
   Printf.printf " Added (%f, %f)\n" new_point_array.(0)#get_latitude new_point_array.(0)#get_longitude;
  new_path#set_points new_point_array;
 

  (*Printf.printf "first list %s \n second list %s";*)
  pathArray.(path_num.contents) <- new_path;
  path_named_arr.(path_num.contents) <- name;
  path_num := !path_num+1;
  if debug = "true" then
    Printf.printf "added path object:%s to array\n" new_path#get_name

(*adds intersection object to the array*)
let add_intersection name weight path_1 path_2 x1 y1 =
  let new_intersection = new intersection in
  new_intersection#set_name name;
  new_intersection#set_weight weight;
  new_intersection#set_path_one path_1;
  new_intersection#set_path_two path_2;
  new_intersection#set_point x1 y1;
  intersArray.(intersection_num.contents) <- new_intersection;
  inters_named_arr.(intersection_num.contents) <- name;
  intersection_num := !intersection_num+1;
  if debug = "true" then
    Printf.printf "added intersection object:%s to array\n" new_intersection#get_name

(*now that we know how many instances of each object is in the xml, we can go through the file again and add the object to the initialized array*)
let xml_parser_2 =
  let x = Xml.parse_file "MapMeObjects.xml" in
  Xml.iter (function
  Xml.Element ("myobject", attrs, _) ->
    List.iter (function ("description", desc) -> 
      if desc = "path" then
	let name = List.assoc "name" attrs and
            p_type = List.assoc "type" attrs and 
	    n_points = int_of_string(List.assoc "numOfPoints" attrs) and
	    points = List.assoc "points" attrs in
	add_path name p_type n_points points
      else if desc = "mapObject" then
	let name = List.assoc "name" attrs and
	    o_type = List.assoc "type" attrs and
	    point = List.assoc "point" attrs and
	    speed = int_of_string(List.assoc "speed" attrs) in
	add_mapObject name o_type point speed
      else if desc = "intersection" then
	let name = List.assoc "name" attrs and
	    weight = float_of_string(List.assoc "weight" attrs) and
	    point = float_of_string(List.assoc "point" attrs) and
	    point_2 = float_of_string(List.assoc "point" attrs) and
	    path_1 = List.assoc "path1" attrs and
	    path_2 = List.assoc "path2" attrs in
	add_intersection name weight path_1 path_2 point point_2
      else if desc = "point\n" then
          Printf.printf "this is a point"
      else Printf.printf "not a recognizable object\n" | _ -> ()) attrs
    | _ -> ()) x

(*below are methods used to find the index of the searched array *)
let find_index_objectArray name = 
  let rec loop i = 
    if i >= Array.length  object_named_arr then -1 
    else if  object_named_arr.(i) = name then i
    else loop(i+1) in 
loop 0

let find_index_pathArray name = 
  let rec loop i = 
    if i >= Array.length  path_named_arr then -1 
    else if  path_named_arr.(i) = name then i
    else loop(i+1) in 
loop 0

(*calculate distance*)
let get_distance object_1 object_2 =
  let point1 = objArray.(find_index_objectArray object_1)#get_point.(0) and
      point2 = objArray.(find_index_objectArray object_2)#get_point.(0) and
      r = 6371.0 and pi = 4.0 *. atan 1.0 in
	((acos ((sin (point1#get_latitude *. pi /. 180.0))*.(sin (point2#get_latitude*. pi /. 180.0))+.(cos (point1#get_latitude*. pi /. 180.0))*.(cos (point2#get_latitude *. pi /. 180.0))*.(cos ((point2#get_longitude*. pi /. 180.0)-.(point1#get_longitude*. pi /. 180.0))))) *. r) *. 0.62137

(*retrieve the total amount of objects in the mapObjects array*)
(*arg should be either the string: mapObject or path*)
let get_num_of_objects object_name = 
  if object_name = "mapObject" then
    Array.length objArray
  else if object_name = "path" then
    Array.length pathArray
  else
    raise Not_found

(*find intersection given two string path names*)
let find_intersection p1_name p2_name =
  let index_p1 = find_index_pathArray p1_name and
  index_p2 = find_index_pathArray p2_name and
  intersection_object = new intersection in
  let p1 = pathArray.(index_p1) and
      p2 = pathArray.(index_p2) in
  (*find the index of the path*)
  let intersection_point = new point in
  let x0_1 = p1#get_points.(0)#get_longitude and
  y0_1 = p1#get_points.(0)#get_latitude and
  x1_1 = p1#get_points.((Array.length p1#get_points) - 1)#get_longitude and
  y1_1 = p1#get_points.((Array.length p1#get_points) - 1)#get_latitude and
  x0_2 = p2#get_points.(0)#get_longitude and
  y0_2 = p2#get_points.(0)#get_latitude and
  x1_2 = p2#get_points.((Array.length p2#get_points) - 1)#get_longitude and
  y1_2 = p2#get_points.((Array.length p2#get_points) - 1)#get_latitude in
  if ((y0_1 <= y0_2 && y0_2 < y1_1) && ((x0_1 -. 0.001000 <= x0_2 && x0_2 < x0_1 +. 0.001000) || (x0_1 -. 0.001000 <= x1_2 && x1_2 < x0_1 +. 0.001000))) then begin
    intersection_point#set_longitude x0_1;
    intersection_point#set_latitude y0_2;
    if debug = "true" then
      Printf.printf "intersection at (%f, %f)\n" y0_2 x0_1;
    let string_name = p1_name^"_"^p2_name in
    intersection_object#set_name string_name;
    if debug = "true" then
      Printf.printf "intersection name: %s\n" string_name;
    intersection_object#set_weight 0.0;
    intersection_object#set_path_one p1_name;
    intersection_object#set_path_two p2_name;
    intersection_object#set_point y0_2 x0_1;
    intersArray.(intersection_num.contents) <- intersection_object;
    inters_named_arr.(intersection_num.contents) <- string_name;
    intersection_num := !intersection_num+1;
    if debug = "true" then
      Printf.printf "added intersection object: %s to array\n" inters_named_arr.(intersection_num.contents -1); 
    string_name
  end
  else begin
    let s = "none" in
    intersection_point#set_longitude 10000.000000;
    intersection_point#set_latitude 10000.000000;
    if debug = "true" then
      Printf.printf "NO INTERSECTION\n";
    s
  end

let q = pathArray.(0)#get_name
let w = pathArray.(2)#get_name
let ip = find_intersection q w
let q = pathArray.(0)#get_name
let w = pathArray.(4)#get_name
let ip = find_intersection q w

let pointArray = Array.make 100 point

(*********************************************************************************************)

module StringHash = Hashtbl.Make(struct
  type t = string
  let equal x y = x = y
  let hash = Hashtbl.hash
end)

let myhash = StringHash.create 17;;
StringHash.add myhash "first" ""

let slisthash = StringHash.create 17;;
StringHash.add slisthash "first" [""]

module HashMap = Map.Make(String)
let hmap = HashMap.empty
let hmap = HashMap.add "myhash" 0 hmap

module SlHashMap = Map.Make(String)
let slhmap = SlHashMap.empty


module FunctionMap = Map.Make(String)
let fmap = FunctionMap.empty
let fmap = FunctionMap.add "print_int" 1 fmap
let fmap = FunctionMap.add "print_str" 2 fmap

module NameMap = Map.Make (struct
 type t = string
 let compare x y = Pervasives.compare x y
end)
let funcmap = NameMap.empty

module TypeMap = Map.Make(String)
let tmap = TypeMap.empty
let tmap = TypeMap.add "int" 1 tmap
let tmap = TypeMap.add "string" 2 tmap

module IdMap = Map.Make(String)
let imap = IdMap.empty
let imap = IdMap.add "Hello" 2 imap
let imap = IdMap.add "hi" 3 imap

module StringListMap = Map.Make(String)
let slistmap = StringListMap.empty

module IntMap = Map.Make(String)
let intmap = IntMap.empty

module FloMap = Map.Make(String)
let flomap = FloMap.empty

module StringMap = Map.Make(String)
let strmap = StringMap.empty

module IntarrMap = Map.Make(String)
let intarrmap = IntarrMap.empty

let intArray = Array.make 50 0
let floArray = Array.make 50 0.0
let strArray = Array.make 50 ""
let strlistArray = Array.make 50 [""]
let array_int = Array.make 30 intArray
let hashArray = Array.make 5 myhash
let slhashArray = Array.make 5 slisthash

let stringTemp = ""
let int_num =ref 0
let flo_num =ref 0
let str_num =ref 0
let intarr_num =ref 0
let func_num = ref 3
let slist_num = ref 0
let shash_num = ref 1
let slhash_num = ref 0
let addone = fun num -> num+1
(*let intAdd = fun id int_num ->if (IntMap.mem id intmap)then( raise (Failure("redeclared variable")))
                        else(let intmap = IntMap.add id int_num intmap in intmap)*)
(*let intAdd id int_num = if (IntMap.mem id intmap)then( raise (Failure("redeclared variable")))
                        else(let intmap=IntMap.add id int_num intmap )*)

let assignment = fun id expr -> if (IntMap.mem id intmap)then(intArray.(IntMap.find id intmap) <- expr;expr )  
                                else raise (Failure("undeclared int variable"))          

let first = fun (x,y,z,s,p,pr) -> x
let second = fun (x,y,z,s,p,pr) -> y
let third = fun (x,y,z,s,p,pr) -> z
let four = fun (x,y,z,s,p,pr) -> s
let five = fun (x,y,z,s,p,pr)->p
let six = fun (x,y,z,s,p,pr)->pr

let execList l f = List.hd (List.rev (List.map f l) )
(*let execList l f m = List.fold_left f m l*)
let print_int = fun s ->let a = print_endline(string_of_int (List.hd s)) in List.hd s
let print_str = fun s ->let a = print_endline strArray.(List.hd s) in 11
                   
let add = fun s ->let a =print_endline(string_of_int( List.hd s + List.hd (List.tl s))) in 2

let callnew = fun index varible -> match index with
    1 -> print_int varible
|   2 -> print_str varible

let getbody funclist = List.map ( fun func->func.body ) funclist 

let varSlhash slhmap stmtl =
let slhashAdd = fun slhmap id slhash_num ->if (SlHashMap.mem id slhmap)then( raise (Failure("redeclared variable")))
                        else(let slhmap = SlHashMap.add id slhash_num slhmap in slhmap )
in
let rec exprid slhmap = function
  SLcre(id) -> 
    ((ignore (slhash_num:=!slhash_num+1);slhash_num.contents), (slhashAdd slhmap id slhash_num.contents))
 | _ -> (0,slhmap)
in
 	let rec stmtid slhmap= function
      	    Expr(e) ->
        	exprid slhmap e
	  | Block(b) ->
                (1,(List.fold_left (fun slhmap stmt -> snd(stmtid slhmap stmt) ) slhmap b))
          | _ -> (0,slhmap)
in stmtid slhmap stmtl

let sndvarSlhash slhmap stmtl = snd(varSlhash slhmap stmtl)

let vSlhash slhmap prog=
let stmtlist = getbody prog 
in
let a = List.fold_left (fun slhmap stmtl -> sndvarSlhash slhmap stmtl) slhmap stmtlist 
in a

let varShash hmap stmtl =
let shashAdd = fun hmap id shash_num ->if (HashMap.mem id hmap)then( raise (Failure("redeclared variable")))
                        else(let hmap = HashMap.add id shash_num hmap in hmap )
in
let rec exprid hmap = function
  Scre(id) -> 
    ((ignore (shash_num:=!shash_num+1);shash_num.contents), (shashAdd hmap id shash_num.contents))
 | _ -> (0,hmap)
in
 	let rec stmtid hmap= function
      	    Expr(e) ->
        	exprid hmap e
	  | Block(b) ->
                (1,(List.fold_left (fun hmap stmt -> snd(stmtid hmap stmt) ) hmap b))
          | _ -> (0,hmap)
in stmtid hmap stmtl

let sndvarShash hmap stmtl = snd(varShash hmap stmtl)

let vShash hmap prog=
let stmtlist = getbody prog 
in
let a = List.fold_left (fun hmap stmtl -> sndvarShash hmap stmtl) hmap stmtlist 
in a

let varList slistmap stmtl =
let listAdd = fun slistmap id slist_num ->if (StringListMap.mem id slistmap)then( raise (Failure("redeclared variable")))
                        else(let slistmap = StringListMap.add id slist_num slistmap in slistmap )
in
let rec exprid slistmap = function
  StringList(id) -> 
    ((ignore (slist_num:=!slist_num+1);slist_num.contents), (listAdd slistmap id slist_num.contents))
 | _ -> (0,slistmap)
in
 	let rec stmtid slistmap= function
      	    Expr(e) ->
        	exprid slistmap e
	  | Block(b) ->
                (1,(List.fold_left (fun slistmap stmt -> snd(stmtid slistmap stmt) ) slistmap b))
          | _ -> (0,slistmap)
in stmtid slistmap stmtl

let sndvarList slistmap stmtl = snd(varList slistmap stmtl)

let vList slistmap prog=
let stmtlist = getbody prog 
in
let a = List.fold_left (fun slistmap stmtl -> sndvarList slistmap stmtl) slistmap stmtlist 
in a

let varint intmap stmtl =
let intAdd = fun intmap id int_num ->if (IntMap.mem id intmap)then( raise (Failure("redeclared variable")))
                        else(let intmap = IntMap.add id int_num intmap in intmap )
in
let rec exprid intmap = function
  Int(id) -> 
    ((ignore (int_num:=!int_num+1);int_num.contents), (intAdd intmap id int_num.contents))
 | _ -> (0,intmap)
in
 	let rec stmtid intmap= function
      	    Expr(e) ->
        	exprid intmap e
	  | Block(b) ->
                (1,(List.fold_left (fun intmap stmt -> snd(stmtid intmap stmt) ) intmap b))
          | _ -> (0,intmap)
in stmtid intmap stmtl

let sndvarint intmap stmtl = snd(varint intmap stmtl)

let vint intmap prog=
let stmtlist = getbody prog 
in
let a = List.fold_left (fun intmap stmtl -> sndvarint intmap stmtl) intmap stmtlist 
in a

let varflo flomap stmtl =
let floAdd = fun flomap id flo_num ->if (FloMap.mem id flomap)then( raise (Failure("redeclared variable")))
                        else(let flomap = FloMap.add id flo_num flomap in flomap )
in
let rec exprid flomap = function
  Flo(id) -> 
    ((ignore (flo_num:=!flo_num+1);flo_num.contents), (floAdd flomap id flo_num.contents))
 | _ -> (0,flomap)
in
 	let rec stmtid flomap= function
      	    Expr(e) ->
        	exprid flomap e
	  | Block(b) ->
                (1,(List.fold_left (fun flomap stmt -> snd(stmtid flomap stmt) ) flomap b))
          | _ -> (0,flomap)
in stmtid flomap stmtl

let sndvarflo flomap stmtl = snd(varflo flomap stmtl)

let vflo flomap prog=
let stmtlist = getbody prog 
in
let a = List.fold_left (fun flomap stmtl -> sndvarflo flomap stmtl) flomap stmtlist 
in a

let varstr strmap stmt =
let strAdd = fun strmap id str_num ->if (StringMap.mem id strmap)then( raise (Failure("redeclared variable")))
                        else(let strmap = StringMap.add id str_num strmap in strmap )
in
let rec exprid strmap = function
  Stringv(id) -> 
    ((ignore (str_num:=!str_num+1);str_num.contents), (strAdd strmap id str_num.contents))
 | _ -> (0,strmap)
in
 	let rec stmtid strmap= function
      	    Expr(e) ->
        	exprid strmap e
	  | Block(b) ->
                (1,(List.fold_left (fun strmap stmt -> snd(stmtid strmap stmt) ) strmap b))
          | _ -> (0,strmap)
in stmtid strmap stmt

let sndvarstr strmap stmtl = snd(varstr strmap stmtl)

let vstr intmap prog=
let stmtlist = getbody prog 
in
let a = List.fold_left (fun strmap stmtl -> sndvarstr strmap stmtl) strmap stmtlist 
in a

let intarr intarrmap stmt =
let intarrAdd = fun intarrmap id intarr_num ->if (IntarrMap.mem id intarrmap)then( raise (Failure("redeclared variable")))
                        else(let intarrmap = StringMap.add id intarr_num intarrmap in intarrmap )
in
let rec exprid intarrmap = function
  IntArray(id,n) -> 
    ((ignore (intarr_num:=!intarr_num+1);intarr_num.contents), ((array_int.(intarr_num.contents)<-(Array.make n 0));intarrAdd intarrmap id intarr_num.contents))
 | _ -> (0,intarrmap)
in
 	let rec stmtid intarrmap= function
      	    Expr(e) ->
        	exprid intarrmap e
	  | Block(b) ->
                (1,(List.fold_left (fun intarrmap stmt -> snd(stmtid intarrmap stmt) ) intarrmap b))
          | _ -> (0,intarrmap)
in stmtid intarrmap stmt

let sndintarr intarrmap stmtl = snd(intarr intarrmap stmtl)

let iarr intarrmap prog=
let stmtlist = getbody prog 
in
let a = List.fold_left (fun intarrmap stmtl -> sndintarr intarrmap stmtl) intarrmap stmtlist 
in a

let funcdecl prog =
   let funcmap = List.fold_left
       (fun funcs fdecl -> NameMap.add fdecl.fname fdecl funcs)
       funcmap prog
   in funcmap

let stringList = [""]

let traslate stringTemp stringList intmap strmap intarrmap funcmap flomap slistmap hmap slhmap prog =

let rec call statement=
let rec expr = function 
    Id(s) -> ((if(IntMap.mem s intmap) then (intArray.(IntMap.find s intmap) ,stringTemp,0.0,stringList,point,pointArray)
                else if(StringMap.mem s strmap) then (0,strArray.(StringMap.find s strmap),0.0,stringList,point,pointArray)
                else if(FloMap.mem s flomap) then (0,stringTemp,floArray.(FloMap.find s flomap),stringList,point,pointArray)
                else if(StringListMap.mem s slistmap) then (0,stringTemp,0.0,(strlistArray.(StringListMap.find s slistmap)),point,pointArray)
                else raise (Failure("undeclared inttt variable"))))

  | Print(s)->((if(IntMap.mem s intmap) then (ignore(print_endline(string_of_int(intArray.(IntMap.find s intmap))));(intArray.(IntMap.find s intmap) ,stringTemp,0.0,stringList,point,pointArray))
                else if(StringMap.mem s strmap) then (ignore(print_endline(strArray.(StringMap.find s strmap))); (0,strArray.(StringMap.find s strmap),0.0,stringList,point,pointArray))
                else if(FloMap.mem s flomap) then(ignore(print_endline(string_of_float(floArray.(FloMap.find s flomap)))); (0,stringTemp,floArray.(FloMap.find s flomap),stringList,point,pointArray))
                else if(StringListMap.mem s slistmap) then(ignore(List.map (fun s -> ignore(print_endline s);s) strlistArray.(StringListMap.find s slistmap)); (0,stringTemp,0.0,(strlistArray.(StringListMap.find s slistmap)),point,pointArray))
                else raise (Failure("undeclared inttt variable"))))
  | Intersect(a1,a2)->
    let s1 = second(expr a1) and s2 = second(expr a2) in
      (*call the intersection here using s1,s2 as arguments*)
       let inters = find_intersection s1 s2 in
      (0,inters,0.0,stringList,point,pointArray)
  | Strcmp(e1,e2) ->
    let s1=second (expr e1) and s2=second(expr e2) in
    let a = if(s1=s2)then 1 else 0 in
    (a,stringTemp,0.0,stringList,point,pointArray)
  | GetDistance(a1,a2)->
    let s1 = second(expr a1) and s2 = second(expr a2) in
    let distance = get_distance s1 s2 in
    (0,stringTemp,distance,stringList,point,pointArray)
  | Int (id) ->
      (0,stringTemp,0.0,stringList,point,pointArray)
      (*((ignore (int_num:=!int_num+1);int_num.contents), (intAdd id int_num.contents))*)
  | ObjArray(id,index,t) ->(*inters[i].name*)
    let i=first(expr index) in
    let a = strArray.(i) in
    if(id="pathArray") then
    (match t with
     "name"->(1,pathArray.(i)#get_name,0.0,stringList,point,pointArray)
    |"pathType" -> (2,pathArray.(i)#get_pathType,0.0,stringList,point,pointArray)
    |"numberOfPoints" -> (pathArray.(i)#get_numberOfPoints,stringTemp,0.0,stringList,point,pointArray)
    |"points" ->(3,stringTemp,0.0,stringList,point,pathArray.(i)#get_points)
    )
    else if(id="objArray") then
    (match t with
     "name" ->(1,objArray.(i)#get_name,0.0,stringList,point,pointArray)
    |"objectType"-> (2,objArray.(i)#get_objectType,0.0,stringList,point,pointArray)
    |"speed" ->(objArray.(i)#get_speed,stringTemp,0.0,stringList,point,pointArray)
    |"length"->(Array.length objArray,stringTemp,0.0,stringList,point,pointArray)
    )
    else if(id="intersArray") then
    (match t with
     "name" ->(1,intersArray.(i)#get_name,0.0,stringList,point,pointArray)
    |"weight" ->(1,stringTemp,intersArray.(i)#get_weight,stringList,point,pointArray)
    |"path1"->(2,intersArray.(i)#get_path_one,0.0,stringList,point,pointArray)
    |"path2"->(2,intersArray.(i)#get_path_two,0.0,stringList,point,pointArray)
    |"point" ->(2,stringTemp,0.0,stringList,intersArray.(i)#get_point,pointArray)
    )
    else(3,stringTemp,0.0,stringList,point,pointArray)
  | Objpoint(id1,index,id2,t)-> (*intersArray.point.latitude;*)
    let i = index in
    if(id1="intersArray") then (match t with 
	"latitude" -> (3,stringTemp,intersArray.(i)#get_point#get_latitude,stringList,point,pointArray)
      |"longitude"->(3,stringTemp,intersArray.(i)#get_point#get_longitude,stringList,point,pointArray))
    else(2,stringTemp(*objArray.(i)#get_pathType *),0.0,stringList,point,pointArray)
  | Onedot(id,t) -> (*inters.length*)
    if(id="pathArray") then (match t with 
	"length" -> (Array.length pathArray,stringTemp,0.0,stringList,point,pointArray))
    else if (id="intersArray")then (match t with 
	"length" -> (Array.length intersArray,stringTemp,0.0,stringList,point,pointArray))
    else if (id="objArray")then (match t with 
	"length" -> (Array.length objArray,stringTemp,0.0,stringList,point,pointArray))
    else if (find_index_objectArray id != -1) then (match t with 
	"name" -> (2,objArray.(find_index_objectArray id)#get_name,0.0,stringList,point,pointArray)
      | "objectType" -> (2,objArray.(find_index_objectArray id)#get_objectType,0.0,stringList,point,pointArray)
      | "point" -> (2,stringTemp,0.0,stringList,objArray.(find_index_objectArray id)#get_point.(0),pointArray)
      | "speed" -> (objArray.(find_index_objectArray id)#get_speed,stringTemp,0.0,stringList,point,pointArray))    
    else (3,stringTemp,0.0,stringList,point,pointArray)
  | Twodot(id1,i1,id2,i2,t)-> (*pathArray[i].points[j].latitude*)
    let index1 = first(expr i1) and index2 = first(expr i2) in
    if(id1="pathArray") then (match t with 
	"latitude" -> (3,stringTemp,pathArray.(index1)#get_points.(index2)#get_latitude,stringList,point,pointArray)
      |"longitude"->(3,stringTemp,pathArray.(index1)#get_points.(index2)#get_longitude,stringList,point,pointArray))
    else if (id1="objArray")then (match t with 
	"latitude" -> (3,stringTemp,objArray.(index1)#get_point.(index2)#get_latitude,stringList,point,pointArray)
      |"longitude"->(3,stringTemp,objArray.(index1)#get_point.(index2)#get_longitude,stringList,point,pointArray))
    else (3,stringTemp,0.0,stringList,point,pointArray)
  | Flo (id) ->
      (0,stringTemp,0.0,stringList,point,pointArray)
  | Stringv(i) ->
      (1,stringTemp,0.0,stringList,point,pointArray)
  | Scre(id)  ->
      (1,stringTemp,0.0,stringList,point,pointArray)
  | SLcre(id) ->
      (1,stringTemp,0.0,stringList,point,pointArray)
  | Sadd(id,s1,s2) ->
ignore(
      let a2=expr s2 in
      if (HashMap.mem id hmap)
      then(StringHash.add hashArray.(HashMap.find id hmap) s1 (second a2)) 
      else raise (Failure("undeclared hashmap variable"))
      );
      (66,(StringHash.find hashArray.(HashMap.find id hmap) s1),0.0,stringList,point,pointArray)
  | Smem(id,s1) ->
    let a =
    if(HashMap.mem id hmap)then(if(StringHash.mem hashArray.(HashMap.find id hmap) s1)then 1 else 0)
    else raise (Failure("undeclared hashmap variable")) in
    (a,stringTemp,0.0,stringList,point,pointArray)
  | Sfind(id,s1) ->
    let a =
    if (HashMap.mem id hmap)
      then(if(StringHash.mem hashArray.(HashMap.find id hmap) s1)then(StringHash.find hashArray.(HashMap.find id hmap) s1 )else raise (Failure("member not found"))) 
      else raise (Failure("undeclared hashmap variable")) in
    (0,a,0.0,stringList,point,pointArray)
  | SLadd(id,s1,s2) ->
ignore(
      let a2=expr s2 in
      if (SlHashMap.mem id slhmap)
      then(StringHash.add slhashArray.(SlHashMap.find id slhmap) s1 (four a2)) 
      else raise (Failure("undeclared slhashmap variable"))
      );
      (66,stringTemp,0.0,(StringHash.find slhashArray.(SlHashMap.find id slhmap) s1),point,pointArray)
  | SLmem(id,s1) ->
    let a =
    if(SlHashMap.mem id slhmap)then(if(StringHash.mem slhashArray.(SlHashMap.find id slhmap) s1)then 1 else 0)
    else raise (Failure("undeclared hashmap variable")) in
    (a,stringTemp,0.0,stringList,point,pointArray)
  | SLfind(id,s1) ->
    let a =
    if (SlHashMap.mem id slhmap)
      then(if(StringHash.mem slhashArray.(SlHashMap.find id slhmap) s1)then(StringHash.find slhashArray.(SlHashMap.find id slhmap) s1 )else raise (Failure("member not found"))) 
      else raise (Failure("undeclared hashmap variable")) in
    (0,stringTemp,0.0,a,point,pointArray)
  | Slist(slist) ->
      let s= List.map (fun s-> String.sub s 1 ((String.length s)-2)) slist in 
      let l = List.rev s in
      (77,stringTemp,0.0,l,point,pointArray)
  | StringList(id)->
      (88,stringTemp,0.0,stringList,point,pointArray)
  | StringListAdd(id,s1)->
    let s = second(expr s1) in
    let a =
    if(StringListMap.mem id slistmap) then (s::strlistArray.(StringListMap.find id slistmap))
    else raise (Failure("undeclared StringList ")) in
    ignore(strlistArray.(StringListMap.find id slistmap) <- a);(67,stringTemp,0.0,strlistArray.(StringListMap.find id slistmap),point,pointArray)
  | Return(e) -> expr e
  | Not(e) -> 
    ((let int_bool = function
         1->true
       | 0->false  
    in
    let a=first(expr e) in
     if (not (int_bool a)) then 1 else 0
    ),stringTemp,0.0,stringList,point,pointArray)
  | IntArray(id,n) -> 
      (2,stringTemp,0.0,stringList,point,pointArray)
  | Char (c) -> ((int_of_char c),stringTemp,0.0,stringList,point,pointArray)
  | Str (s) -> (1,(String.sub s 1 ((String.length s)-2)),0.0,stringList,point,pointArray)
 (* | Call (fname, actuals) -> 
      ((let v1 = FunctionMap.find fname fmap and v2 =List.map (fun a -> fst(expr a)) actuals in 
      call v1 v2),stringTemp)*)
  | Call (fname, actuals) ->
      if(NameMap.mem fname funcmap) then 

      let actual=List.map expr actuals in
         let rec varAssign = function
         ([],[]) -> 0
       | (v1::tl1,[]) -> raise (Failure("variable not match"))
       | ([],v2::tl2) -> raise (Failure("variable not match"))
       | (v1::tl1,v2::tl2) -> if (IntMap.mem v1 intmap)then((intArray.(IntMap.find v1 intmap) <- (first(v2)));varAssign (tl1,tl2))
                    else if (StringMap.mem v1 strmap) then ((strArray.(StringMap.find v1 strmap) <- (second(v2)));varAssign (tl1,tl2))
                    else if (FloMap.mem v1 flomap) then ((floArray.(FloMap.find v1 flomap) <- (third(v2)));varAssign (tl1,tl2))
                                else raise (Failure("undeclared variable of the function")) 
       in
          ignore(varAssign ((NameMap.find fname funcmap).formals,actual));call(NameMap.find fname funcmap).body
          
      else raise (Failure("function is not defined")) 
      (*print_endline (fname);FunctionMap.find fname fmap*)
  (*| Seq (expr1, expr2) ->
      ignore(expr expr1); expr expr2*)
  | Lit(x) -> (x,stringTemp,0.0,stringList,point,pointArray)  
  | Float(x) -> (*print_endline ( string_of_float(x));*)(99,stringTemp,x,stringList,point,pointArray)
  | Assign(id,e) -> if (IntMap.mem id intmap)then((intArray.(IntMap.find id intmap) <- (first(expr e));(first(expr e))),stringTemp,0.0 ,stringList,point,pointArray)  
                    else if (StringMap.mem id strmap) then ((strArray.(StringMap.find id strmap) <- (second(expr e));(first(expr e))),second(expr e),0.0 ,stringList,point,pointArray) 
                    else if (FloMap.mem id flomap)then((floArray.(FloMap.find id flomap) <- (third(expr e));(first(expr e))),stringTemp,(third(expr e)) ,stringList,point,pointArray)
                    else if (StringListMap.mem id slistmap)then((strlistArray.(StringListMap.find id slistmap) <- (four(expr e));(first(expr e))),stringTemp,(third(expr e)) ,strlistArray.(StringListMap.find id slistmap),point,pointArray)
                                else raise (Failure("undeclared int variable")) 
  | ArrAssign(id,n,e) -> if (IntarrMap.mem id intarrmap) then (((array_int.(IntarrMap.find id intarrmap).(n) <- first(expr e));first(expr e)),second (expr e),0.0,stringList,point,pointArray)
                                else raise (Failure("undeclared int variable")) 
  | Binop(e1, op, e2) ->
      ((let v1 = first(expr e1) and v2 = first(expr e2) in
       let int_bool = function
         1->true
       | 0->false  in
      match op with
	Add -> v1 + v2
      | Sub -> v1 - v2
      | Mul -> v1 * v2
      | Div -> v1 / v2
      | Equal -> if(v1=v2) then 1 else 0
      | Neq -> if(v1!=v2) then 1 else 0
      | Greater -> if(v1>v2) then 1 else 0
      | Less -> if(v1<v2) then 1 else 0
      | Geq -> if(v1>=v2) then 1 else 0
      | Leq -> if(v1<=v2) then 1 else 0
      | And ->    
        if((int_bool v1)&&(int_bool v2)) then 1 else 0
      | Or ->
        if((int_bool v1))||((int_bool v2)) then 1 else 0
     
      ),stringTemp,0.0,stringList,point,pointArray)

  | FBinop(e1, op, e2) ->(0,stringTemp,
      (let v1 = third(expr e1) and v2 = third(expr e2) in
      match op with
	Fadd -> v1 +. v2
      | Fsub -> v1 -. v2
      | Fmul -> v1 *. v2
      | Fdiv -> v1 /. v2),stringList,point,pointArray)
in 
  let rec stmt= function
   Expr(e) ->
     expr  e 
   | Block(b) ->
      execList b stmt
   | While(e,s) ->
     let rec loop e s = 
      let v = expr e in
       if(first(v)!=0) then ((*print_endline ( string_of_int(first(v)));*)ignore(stmt s);loop e s) else (99,stringTemp,0.0,stringList,point,pointArray)   
         in loop e s
   | If(c,i,e) ->
     let v = expr c in
      if(first(v)!=0) then (stmt i) else (stmt e)

in stmt  statement
in 
   if (NameMap.mem "main" funcmap) then call(NameMap.find "main" funcmap).body
   else raise (Failure("cannot find the main function")) 

(*let _ =
let lexbuf = Lexing.from_channel stdin in
  let program = Parser.stmt Scanner.token lexbuf in
  let intmap = snd(traslate intmap program) in intmap*)

(*read in files *)
(* files will be read in like: ./compile filename *)
let filename = Sys.argv.(1)
let stdin = open_in filename
(* do whatever you need to do to get the data here *)

let _ =
  let lexbuf = Lexing.from_channel stdin in
  let program = Parser.program Scanner.token lexbuf in
  (*let intmap = snd(varint intmap program) in*)
  let intmap = vint intmap program in
  (*let strmap = snd(varstr strmap program) in*)
  let strmap = vstr strmap program in
  (*let intarrmap = snd(intarr intarrmap program) in*)
  let intarrmap = iarr intarrmap program in
  let funcmap = funcdecl program in
  let flomap = vflo flomap program in
  let slistmap = vList slistmap program in
  let hmap = vShash hmap program in
  let slhmap = vSlhash slhmap program in
  let result = traslate stringTemp stringList intmap strmap intarrmap funcmap flomap slistmap hmap slhmap program  in
 (* print_endline (string_of_float(third(result)));*)
  (*print_endline ( string_of_int(first(result)));*)
  (* print_endline (second(result));*)
  List.map (fun s -> ignore(print_endline s);s) (four result);
  result;"test"

let () = close_in stdin

